/************************************************************
 * Filename: Message.h
 * Purpose: Basic message class and message types.
 * Author: Jeremy Kings
 * Revision: 1 (18 November 2010)
 *
 * Copyright 2010, Digipen Institute of Technology
 ************************************************************/
#pragma once

#include "Vector2D.h"
#include "GameObjectTypes.h"
#include "ComponentTypes.h"
#include "SoundTypes.h"
#include "Serializer.h"

namespace Engine
{
	// Forward declaration of game object component (for Component message)
	class ObjectComponent;
	class GameObject;

	// Message types
	enum MessageType
	{
		MT_KeyDown,
		MT_CharDown,

		MT_Build,
		MT_Component,
		MT_Destroy,
		MT_Erase,

		MT_LoadTexture,

		MT_Collision,
		MT_PlaySound,
		MT_MAX
	};

	// base Message class
	class Message
	{
	public:
		Message(MessageType id): TypeID(id){};
		virtual ~Message(){};

		MessageType GetType() { return TypeID; }

	private:
		MessageType TypeID;
	};

	//////////////////////
	// Message subtypes //
	//////////////////////

	// Message to Factory to build an object
	class BuildMessage : public Message
	{
	public:
		BuildMessage(Serializer& serializer)
			: Message(MT_Build)
		{
			serializer.ReadData(ObjType);
			serializer.ReadData(Position);
			serializer.ReadData(Direction);
			serializer.ReadData(Scale);
		}

		BuildMessage(std::string objType, Vector2D pos = Zero(), float dir = 0.0f, float scale = 1.0f)
			: Message(MT_Build),ObjType(objType),Position(pos),Direction(dir),Scale(scale){}

		std::string GetObjectType() { return ObjType; }
		Vector2D GetPos() { return Position; }
		float GetDir() { return Direction; }
		float GetScale() { return Scale; }

	private:
		std::string ObjType;
		Vector2D Position;
		float Direction;
		float Scale;
	};

	// Message to Factory to destroy an object/to systems to erase an object's components
	class DestroyMessage : public Message
	{
	public:
		// Type should either be MT_Destroy or MT_Erase
		DestroyMessage(unsigned instID, GameObjectType objType, MessageType mt = MT_Destroy)
			: Message(mt),InstID(instID),ObjType(objType){};

		unsigned GetInstID() { return InstID; }
		GameObjectType GetObjType() { return ObjType; }

	private:
		unsigned InstID;
		GameObjectType ObjType;
	};

	// Message that a key has been pressed (can be regular or character)
	class KeyDownMessage : public Message
	{
	public:
		KeyDownMessage(int key, MessageType type = MT_KeyDown)
			: Message(type),Key(key){};

		int GetKey() { return Key; }

	private:
		int Key;
	};

	// Message to an object that it has collided with another object.
	class CollisionMessage : public Message
	{
	public:
		CollisionMessage(unsigned instID, GameObjectType objType, float weight)
			: Message(MT_Collision),InstID(instID), ObjType(objType),Weight(weight){};

		unsigned GetInstID() { return InstID; }
		GameObjectType GetObjType() { return ObjType; }
		float GetWeight() { return Weight; }

	private:
		unsigned InstID;
		GameObjectType ObjType; // type of object that the object collided with
		float Weight; // used to determine the amount of damage caused
	};

	class AudioMessage : public Message
	{
	public:
		AudioMessage(Serializer& serializer)
			: Message(MT_PlaySound)
		{
			serializer.ReadData(Num);
		}

		AudioMessage(SoundType num)
			: Message(MT_PlaySound),Num(num) {}

		SoundType GetNum() { return Num; }

	private:
		SoundType Num;
	};

	// Currently only used for loading the background texture, but
	// I'm hoping I can use something similar to allow smarter loading of
	// assets (i.e. don't load it if you don't have to).
	class LoadTextureMessage : public Message
	{
	public:
		LoadTextureMessage(Serializer& serializer)
			: Message(MT_LoadTexture)
		{
			std::string file;
			serializer.ReadData(file);
			Filename = "assets/" + file;
		}

		std::string GetFilename() { return Filename; }

	private:
		std::string Filename;
	};

	/******************************************************************************* 
	 * I don't particularly like this message, as it passes pointers to game object
	 * components, but I wanted to reduce the number of global pointers and pointers 
	 * to other systems as much as possible. If I figure out some better way to have
	 * components add themselves to systems, I'll eliminate this.
	 *******************************************************************************/
	// Message to a system to add a component
	class ComponentMessage : public Message
	{
	public:
		ComponentMessage(unsigned instID, ComponentType type, ObjectComponent* component)
			: Message(MT_Component),InstID(instID), Type(type), Component(component){}

		unsigned GetInstID() { return InstID; }
		ComponentType GetComponentType() { return Type; }
		ObjectComponent* GetComponent() { return Component; }

	private:
		unsigned InstID;
		ComponentType Type;
		ObjectComponent* Component;
	};
}
